package com.dd.cloud.user.service.resource.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dd.cloud.common.enums.ZkExceptionEnum;
import com.dd.cloud.common.exception.ZekeException;
import com.dd.cloud.common.interceptor.UserInterceptor;
import com.dd.cloud.common.utils.Assert;
import com.dd.cloud.common.utils.ValidatorUtils;
import com.dd.cloud.common.vo.LoginInfo;
import com.dd.cloud.user.entity.resource.SpreadInfo;
import com.dd.cloud.user.mapper.resource.SpreadInfoMapper;
import com.dd.cloud.user.req.resource.SpreadInfoSystemCreateReq;
import com.dd.cloud.user.req.resource.SpreadInfoSystemPageReq;
import com.dd.cloud.user.req.resource.SpreadInfoSystemUpdateReq;
import com.dd.cloud.user.req.resource.SpreadInfoSystemUpdateStatusReq;
import com.dd.cloud.user.res.resource.SpreadInfoSystemDetailRes;
import com.dd.cloud.user.res.resource.SpreadInfoSystemPageRes;
import com.dd.cloud.user.service.resource.ISpreadInfoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @author Lx
 * @version 1.0
 * @date 2024/1/29
 */
@Slf4j
@Service
public class SpreadInfoServiceImpl extends ServiceImpl<SpreadInfoMapper, SpreadInfo> implements ISpreadInfoService {

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 查询开屏信息列表
     *
     * @param req
     * @return
     */
    @Override
    public IPage<SpreadInfoSystemPageRes> querySpreadInfoSystemPage(SpreadInfoSystemPageReq req) {
        Assert.verifyStatusIdsParam(req.getClass(), req);
        if (StringUtils.isBlank(req.getStatus())) {
            req.setStatus("1,2,3,4");
        }
        IPage<SpreadInfoSystemPageRes> iPage = req.pagePojo();
        iPage = getBaseMapper().querySpreadInfoSystemPage(iPage, req);
        return iPage;
    }

    /**
     * 创建开屏信息
     *
     * @param req
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createSpreadInfoSystem(SpreadInfoSystemCreateReq req) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.ADMIN).get();
        if (req.getStatus() == null) {
            ValidatorUtils.verify(req, req.getClass());
            if (req.getDate() == 2 && (req.getStart() == null || req.getEnd() == null)) {
                throw new ZekeException(400, "截止日期不能为空");
            }
        } else {
            if (StringUtils.isBlank(req.getTitle())) {
                throw new ZekeException(400, "图片名称不能为空");
            }
        }
        SpreadInfo spreadInfo = new SpreadInfo();
        BeanUtils.copyProperties(req, spreadInfo);
        if (req.getStatus() == null) {
            if (verifySpreadInfoIsShow(null)) {
                spreadInfo.setStatus(2);
            } else {
                spreadInfo.setStatus(1);
            }
        }
        spreadInfo.setLastId(loginInfo.getId());
        spreadInfo.setLastType(loginInfo.getType());
        spreadInfo.setCreateDate(LocalDateTime.now());
        spreadInfo.setUpdateDate(LocalDateTime.now());
        boolean flag = save(spreadInfo);
        if (!flag) {
            throw new ZekeException(ZkExceptionEnum.ADD_ERROR);
        }
    }

    /**
     * 修改开屏信息
     *
     * @param req
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSpreadInfoSystem(SpreadInfoSystemUpdateReq req) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.ADMIN).get();
        if (req.getStatus() == null) {
            ValidatorUtils.verify(req, req.getClass());
            if (req.getDate() == 2 && (req.getStart() == null || req.getEnd() == null)) {
                throw new ZekeException(400, "截止日期不能为空");
            }
        } else {
            if (req.getId() == null) {
                throw new ZekeException(400, "图片id不能为空");
            }
            if (StringUtils.isBlank(req.getTitle())) {
                throw new ZekeException(400, "图片名称不能为空");
            }
        }
        SpreadInfo spreadInfo = new SpreadInfo();
        BeanUtils.copyProperties(req, spreadInfo);
        if (req.getStatus() == null) {
            if (verifySpreadInfoIsShow(req.getId())) {
                spreadInfo.setStatus(2);
            } else {
                spreadInfo.setStatus(1);
            }
        }
        spreadInfo.setLastId(loginInfo.getId());
        spreadInfo.setLastType(loginInfo.getType());
        spreadInfo.setUpdateDate(LocalDateTime.now());
        boolean flag = updateById(spreadInfo);
        if (!flag) {
            throw new ZekeException(ZkExceptionEnum.UPDATE_ERROR);
        }

    }

    /**
     * 验证是否有开屏页面为显示状态
     *
     * @param id 排除id
     * @return true有开屏页面为显示状态 false没有开屏页面为显示状态
     */
    @Override
    public Boolean verifySpreadInfoIsShow(Integer id) {
        QueryWrapper<SpreadInfo> qw = new QueryWrapper<>();
        qw.lambda().eq(SpreadInfo::getStatus, 1);
        if (id != null) {
            qw.lambda().ne(SpreadInfo::getId, id);
        }
        return count(qw) > 0;
    }

    /**
     * 修改开屏信息状态
     *
     * @param req
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSpreadInfoSystemUpdateStatus(SpreadInfoSystemUpdateStatusReq req) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.ADMIN).get();
        if (req.getStatus() == 1) {
            if (verifySpreadInfoIsShow(req.getId())) {
                throw new ZekeException(400, "最多只可显示一张开屏页面，若需显示该开屏页面请先关闭其他开屏图片？");
            }
            if (req.getDate() == null) {
                throw new ZekeException(400, "投放日期不能为空");
            }
            if (req.getDate() == 2 && (req.getStart() == null || req.getEnd() == null)) {
                throw new ZekeException(400, "截止日期不能为空");
            }
        }
        SpreadInfo spreadInfo = new SpreadInfo();
        spreadInfo.setId(req.getId());
        spreadInfo.setDate(req.getDate());
        spreadInfo.setStatus(req.getStatus());
        spreadInfo.setStart(req.getStart());
        spreadInfo.setEnd(req.getEnd());
        spreadInfo.setLastId(loginInfo.getId());
        spreadInfo.setLastType(loginInfo.getType());
        spreadInfo.setUpdateDate(LocalDateTime.now());
        boolean flag = updateById(spreadInfo);
        if (!flag) {
            throw new ZekeException(ZkExceptionEnum.UPDATE_ERROR);
        }
    }

    /**
     * 查询开屏信息详情
     *
     * @param id
     * @return
     */
    @Override
    public SpreadInfoSystemDetailRes querySpreadInfoSystemDetail(Integer id) {
        SpreadInfoSystemDetailRes res = getBaseMapper().querySpreadInfoSystemDetail(id);
        if (res == null) {
            return new SpreadInfoSystemDetailRes();
        }
        res.setStatisticRes(getBaseMapper().querySpreadInfoStatisticData(id));
        return res;
    }

    @Override
    public SpreadInfo querySpreadInfo() {
        LambdaQueryWrapper<SpreadInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SpreadInfo::getStatus, 1).last("limit 1");
        return this.getOne(queryWrapper);
    }

    /**
     * 定时任务修改开屏页面状态
     */
    @Override
    public void taskUpdateStatus() {
        UpdateWrapper<SpreadInfo> uw = new UpdateWrapper<>();
        uw.lambda().eq(SpreadInfo::getDate, 2);
        uw.lambda().eq(SpreadInfo::getStatus, 1);
        uw.lambda().le(SpreadInfo::getEnd, LocalDateTime.now());
        uw.lambda().set(SpreadInfo::getStatus, 3);
        update(uw);
    }

    @Override
    public void advertRecord(Integer id) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo().get();
        String key = "advert_info_" + loginInfo.getId() + "_" + id;
        LocalDateTime midnight = LocalDateTime.ofInstant(new Date().toInstant(),
                        ZoneId.systemDefault()).plusDays(1).withHour(0).withMinute(0)
                .withSecond(0).withNano(0);
        LocalDateTime currentDateTime = LocalDateTime.ofInstant(new Date().toInstant(),
                ZoneId.systemDefault());
        long seconds = ChronoUnit.SECONDS.between(currentDateTime, midnight);
        redisTemplate.opsForValue().set(key, "1", seconds, TimeUnit.SECONDS);
    }

    @Override
    public Integer queryIsUser(Integer id) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo().get();
        String key = "advert_info_" + loginInfo.getId() + "_" + id;
        if (redisTemplate.hasKey(key)) {
            return 1;
        } else {
            return 0;
        }
    }
}
